package dao

import (
	"context"
	"errors"
	"fmt"
	"time"

	"bmember/pkg/util"

	"bmember/pkg/db/pgex"

	"bmember/internal/model"
)

// MemberAccountDao 会员账号
type MemberAccountDao interface {
	//GetAccsByMemberId 根据会员 id 获取账号
	//GetAccsByMemberId(ctx context.Context, brandId, memberId int64) ([]*model.MemberAccount, error)

	// CreateAccount 创建账号
	CreateAccount(ctx context.Context, acc *model.MemberAccount) (int64, error)
	// GetAccById 根据id 获取账号
	GetAccById(ctx context.Context, accId int64) (*model.MemberAccount, error)
	// LockAccById 锁定账号
	LockAccById(ctx context.Context, accId int64) (*model.MemberAccount, error)
	// GetAccByMemberGroup 根据会员id，体系查询账户
	GetAccByMemberGroup(ctx context.Context, memberId, groupId int64) (*model.MemberAccount, error)
	// LockAccByMemberGroup 根据会员id，体系锁定账户
	LockAccByMemberGroup(ctx context.Context, memberId, groupId int64) (*model.MemberAccount, error)
	// UpdateAccIntegralById 更新账号积分
	UpdateAccIntegralById(ctx context.Context, acc *model.MemberAccount) error
	// UpdateAccBalanceById 更新账号积余额
	UpdateAccBalanceById(ctx context.Context, acc *model.MemberAccount) error
	// UpdateAccCardById 更新账号会员卡
	UpdateAccCardById(ctx context.Context, acc *model.MemberAccount) error
	// UpdateConsumptionStat 更新消费统计
	UpdateConsumptionStat(ctx context.Context, c *model.ConsumptionStatistic) error
	// GetConsumptionStat 获取消费统计
	GetConsumptionStat(ctx context.Context, memberId int64) (*model.ConsumptionStatistic, error)
	// GetConsumptionStatByMemberId 获取消费统计
	GetConsumptionStatByMemberId(ctx context.Context, memberIds []int64) ([]*model.ConsumptionStatistic, error)
	// CountAccsByBrandCreateTime 计算领卡数量
	CountAccsByBrandCreateTime(ctx context.Context, brandId int64, start, end time.Time) (uint32, error)
}

type accDaoImpl struct {
	*DaoBase
	name string
}

var accDao MemberAccountDao

// InitMemberAccountDao 初始化 member account
func InitMemberAccountDao() {
	accDao = &accDaoImpl{
		DaoBase: daoBase,
		name:    "dao_member_account",
	}
}

// GetMemberAccountDao 获取 member account dao
func GetMemberAccountDao() MemberAccountDao {
	return accDao
}

//GetAccsByMemberId 根据会员 id 获取账号
func (dao *accDaoImpl) GetAccsByMemberId(ctx context.Context, brandId, memberId int64) ([]*model.MemberAccount, error) {
	var cards []*model.MemberAccount
	query := "SELECT * FROM member_account WHERE brand_id=? AND member_id=? AND deleted_at=0"
	err := dao.db.Query(ctx, &cards, query, brandId, memberId)
	return cards, err
}

// CreateAccount 创建账号
func (dao *accDaoImpl) CreateAccount(ctx context.Context, acc *model.MemberAccount) (int64, error) {
	if acc == nil {
		return 0, nil
	}
	param := []interface{}{
		acc.BrandId,
		acc.GroupId,
		acc.CardId,
		acc.MemberId,
		acc.CardNumber,
		acc.Balance,
		acc.Integral,
		acc.Deposit,
		acc.Status,
		acc.CreatedAt,
		acc.UpdatedAt,
	}
	query := "INSERT INTO member_account (brand_id, group_id, card_id, member_id, card_number, balance, integral, deposit, " +
		"status, created_at, updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)"
	aff, err := dao.db.PgExec(ctx, "id", query, param...)
	if err != nil {
		return 0, err
	}
	lastId, _ := aff.GetLastId()
	return lastId, nil
}

// GetAccById 根据id 获取账号
func (dao *accDaoImpl) GetAccById(ctx context.Context, accId int64) (*model.MemberAccount, error) {
	query := "SELECT * FROM member_account WHERE id=? AND deleted_at=0"
	acc := &model.MemberAccount{}
	err := dao.db.Get(ctx, acc, query, accId)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// LockAccById 根据id 锁定账号
func (dao *accDaoImpl) LockAccById(ctx context.Context, accId int64) (*model.MemberAccount, error) {
	query := "SELECT * FROM member_account WHERE id=? AND deleted_at=0 FOR UPDATE"
	acc := &model.MemberAccount{}
	err := dao.db.Get(ctx, acc, query, accId)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// GetAccByMemberGroup 根据会员id，体系查询账户
func (dao *accDaoImpl) GetAccByMemberGroup(ctx context.Context, memberId, groupId int64) (*model.MemberAccount, error) {
	query := "SELECT * FROM member_account WHERE member_id=? AND group_id=? AND deleted_at=0"
	acc := &model.MemberAccount{}
	err := dao.db.Get(ctx, acc, query, memberId, groupId)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// LockAccByMemberGroup 根据会员id，体系锁定账户
func (dao *accDaoImpl) LockAccByMemberGroup(ctx context.Context, memberId, groupId int64) (*model.MemberAccount, error) {
	query := "SELECT * FROM member_account WHERE member_id=? AND group_id=? AND deleted_at=0 FOR UPDATE"
	acc := &model.MemberAccount{}
	err := dao.db.Get(ctx, acc, query, memberId, groupId)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return acc, err
}

// UpdateAccIntegralById 更新账号积分
func (dao *accDaoImpl) UpdateAccIntegralById(ctx context.Context, acc *model.MemberAccount) error {
	if acc == nil {
		return nil
	}
	query := "UPDATE member_account SET integral=?, updated_at=NOW() WHERE id=? AND deleted_at=0"
	_, err := dao.db.Update(ctx, query, acc.Integral, acc.Id)
	return err
}

// UpdateAccBalanceById 更新账号积余额
func (dao *accDaoImpl) UpdateAccBalanceById(ctx context.Context, acc *model.MemberAccount) error {
	if acc == nil {
		return nil
	}
	query := "UPDATE member_account SET balance=?, updated_at=NOW() WHERE id=? AND deleted_at=0"
	_, err := dao.db.Update(ctx, query, acc.Balance, acc.Id)
	return err
}

// UpdateAccCardById 更新账号会员卡
func (dao *accDaoImpl) UpdateAccCardById(ctx context.Context, acc *model.MemberAccount) error {
	if acc == nil {
		return nil
	}
	query := "UPDATE member_account SET card_id=?, updated_at=? WHERE id=? AND deleted_at=0"
	_, err := dao.db.Update(ctx, query, acc.CardId, acc.UpdatedAt, acc.Id)
	return err
}

// UpdateConsumptionStat 更新消费记录
func (dao *accDaoImpl) UpdateConsumptionStat(ctx context.Context, c *model.ConsumptionStatistic) error {
	if c == nil {
		return nil
	}
	query := "INSERT INTO consumption_statistic (member_id, brand_id, count, money_amount, created_at, updated_at) VALUES " +
		"(?,?,?,?,?,?) ON CONFLICT (member_id) DO UPDATE SET count=consumption_statistic.count+?, " +
		"money_amount=consumption_statistic.money_amount+?, updated_at=?"
	_, err := dao.db.Insert(ctx, query, c.MemberId, c.BrandId, c.Count, c.MoneyAmount, c.CreatedAt, c.UpdatedAt,
		c.Count, c.MoneyAmount, c.UpdatedAt)
	return err
}

// GetConsumptionStat 获取消费记录
func (dao *accDaoImpl) GetConsumptionStat(ctx context.Context, memberId int64) (*model.ConsumptionStatistic, error) {
	c := &model.ConsumptionStatistic{}
	query := "SELECT * FROM consumption_statistic WHERE member_id=?"
	err := dao.db.Get(ctx, c, query, memberId)
	if err != nil && errors.Is(err, pgex.ErrEmpty) {
		return nil, nil
	}
	return c, err
}

// GetConsumptionsByMemberId 获取消费统计
func (dao *accDaoImpl) GetConsumptionStatByMemberId(ctx context.Context, memberIds []int64) ([]*model.ConsumptionStatistic, error) {
	if len(memberIds) == 0 {
		return nil, nil
	}
	var cs []*model.ConsumptionStatistic
	query := "SELECT * FROM consumption_statistic WHERE member_id in ?"
	err := dao.db.Query(ctx, &cs, query, memberIds)
	return cs, err
}

// CountAccsByBrandCreateTime 计算领卡数量
func (dao *accDaoImpl) CountAccsByBrandCreateTime(ctx context.Context, brandId int64, start, end time.Time) (uint32, error) {
	query := "SELECT COUNT(*) FROM member_account WHERE brand_id=? AND deleted_at=0"
	if !util.IsZeroTime(start) {
		query += fmt.Sprintf(" AND created_at>='%s'", util.TimeStdFormat(start))
	}
	if !util.IsZeroTime(end) {
		query += fmt.Sprintf(" AND created_at<'%s'", util.TimeStdFormat(end))
	}
	var cnt uint32
	err := dao.db.Get(ctx, &cnt, query, brandId)
	return cnt, err
}
